package pl.koszolko.documentclustering.ui.dendrogram;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import pl.koszolko.documentclustering.cluster.Dendrogram;
import pl.koszolko.documentclustering.cluster.document.DocumentForClustering;

public class DendrogramDrawer {
	private Node root;
	private double maxX;
	private double maxY;
	private int maxTitleLenght;

	/**
	 * Wylicza wspolrzedne wszystkich klastrow, przygotowuje dane do zapisu do pliku graficznego
	 * @param dendrogram
	 */
	public void prepareDendrogramToDraw(Dendrogram dendrogram) {
		setLabelsForNodes(dendrogram);
		List<Node> clustersToDraw = getInitialClustersToDraw(dendrogram);
		
		maxX = 2;
		while (clustersToDraw.size() > 1) {
			// obliczaj wsporzedne klastrow
			Node n1 = null;
			Node n2 = null;
			int clusterIndex = 0;

			Node n1TMP = null;
			Node n2TMP = null;
			
			double maxSimilarity = 0.0;
			while (clusterIndex < clustersToDraw.size()) {
				n1 = clustersToDraw.get(clusterIndex);
				n2 = getAnotherChild(n1, clustersToDraw);
				++clusterIndex;
				if(n2 != null) {
					//znaleziono parent
					Dendrogram.Node tmpParent = n1.getParentDendrogramNode();
					if(maxSimilarity <= tmpParent.getSimilarity()) {
						maxSimilarity = tmpParent.getSimilarity();
						n1TMP = n1;
						n2TMP = n2;
					}
				}
			}
			
			//ustawienie odpowiednich n1 i n2
			n1 = n1TMP;
			n2 = n2TMP;
			
			// ustawienie wspolrzednych parenta
			double x = maxX + 3;
			double y = countCoordinatesY(n1, n2);
			Node parent = new Node(n1.getParentDendrogramNode(), x, y);
			parent.setChildL(n1);
			parent.setChildR(n2);
			// ustawienie rodzic
			n1.setParent(parent);
			n2.setParent(parent);

			// dodanie parenta do listy, usuniecie z listy obslurzonych klastrow
			clustersToDraw.add(parent);
			clustersToDraw.remove(n1);
			clustersToDraw.remove(n2);

			// ustawienie dlugosci dendrogramu
			setMaxX(x);
			
			//ustawienie maksymalne dlugosci tytulu
			setMaxTitle(n1);
			setMaxTitle(n2);
		}

		// ustaw ostatniego klastra jako root
		root = clustersToDraw.get(0);
	}

	private void setMaxTitle(Node n1) {
		String title = n1.getDocumentTitle();
		if(title != null && title.length() > maxTitleLenght) {
			maxTitleLenght = title.length();
		}
	}

	/**
	 * Tworzy tekstowy zapis wyniku grupowania
	 * @param dendrogram
	 * @return
	 */
	public List<String> setLabelsForNodes(Dendrogram dendrogram) {
		List<String> clustersLabels = new ArrayList<String>();
		
		for (Dendrogram.Node c : dendrogram.getClusters()) {
			String label = "";
			if (c.getCluster().getDocuments().size() == 1) {
				DocumentForClustering document = (DocumentForClustering) (c
						.getCluster().getDocuments().toArray())[0];

				Dendrogram.Node parent = c.getParent();
				while (parent != null) {
					label = "/" + parent.getNr() + label;
					parent = parent.getParent();
				}

				label += "/" + document.getTitle() + " id "
						+ document.getId();

				clustersLabels.add(label);
			}
			
		}
		
		return clustersLabels;
	}

	private double countCoordinatesY(Node n1, Node n2) {
		return (n1.getY() + n2.getY()) * 0.5;
	}

	private List<Node> getInitialClustersToDraw(Dendrogram dendrogram) {
		List<Dendrogram.Node> initialClusters = dendrogram.getInitialClusters();
		Collections.sort(initialClusters, new NodeComparator());
		List<Node> clustersToDraw = setCoordinates(initialClusters);
		return clustersToDraw;
	}

	private List<Node> setCoordinates(
			List<pl.koszolko.documentclustering.cluster.Dendrogram.Node> initialClusters) {
		List<Node> clustersToDraw = new ArrayList<Node>();
		int y = 1;

		for (Dendrogram.Node node : initialClusters) {
			clustersToDraw.add(new Node(node, 2, y));
			y += 3;
		}

		setMaxY(y);

		return clustersToDraw;
	}

	private Node getAnotherChild(Node node, List<Node> clustersToDraw) {
		Dendrogram.Node parent = node.getParentDendrogramNode();

		if (parent != null) {
			for (Node n : clustersToDraw) {
				if (parent.equals(n.getParentDendrogramNode())
						&& !n.equals(node)) {
					return n;
				}
			}
		}

		return null;
	}

	public double getMaxX() {
		return maxX;
	}

	public void setMaxX(double maxX) {
		this.maxX = maxX;
	}

	public double getMaxY() {
		return maxY;
	}

	public void setMaxY(double maxY) {
		this.maxY = maxY;
	}

	public Node getRoot() {
		return root;
	}

	public void setRoot(Node root) {
		this.root = root;
	}

	public int getMaxTitleLenght() {
		return maxTitleLenght;
	}

	public void setMaxTitleLenght(int maxTitleLenght) {
		this.maxTitleLenght = maxTitleLenght;
	}
}
